package com.stars.easyms.base.util;

import lombok.extern.slf4j.Slf4j;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 日期工具类
 *
 * @author guoguifang
 * @date 2018-10-19 10:07
 * @since 1.0.0
 */
@Slf4j
public final class DateTimeUtil {

    private static final DateTimeFormatter DATETIME_FORMAT_NORMAL_SSS = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");

    private static final DateTimeFormatter DATETIME_FORMAT_NORMAL = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    private static final DateTimeFormatter DATE_FORMAT_NORMAL = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    private static final DateTimeFormatter TIME_FORMAT_NORMAL = DateTimeFormatter.ofPattern("HH:mm:ss");

    private static final DateTimeFormatter DATETIME_FORMAT_SHORT_SSS = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");

    private static final DateTimeFormatter DATETIME_FORMAT_SHORT = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");

    private static final DateTimeFormatter DATE_FORMAT_SHORT = DateTimeFormatter.ofPattern("yyyyMMdd");

    private static final DateTimeFormatter TIME_FORMAT_SHORT = DateTimeFormatter.ofPattern("HHmmss");

    /**
     * 获取本地当前时间 "yyyy-MM-dd HH:mm:ss.SSS"
     */
    public static String now() {
        return DATETIME_FORMAT_NORMAL_SSS.format(
                LocalDateTime.ofInstant(Instant.ofEpochMilli(System.currentTimeMillis()), ZoneId.systemDefault()));
    }

    /**
     * 获取yyyy-MM-dd HH:mm:ss.SSS格式的字符串
     */
    public static String getDatetimeNormalStrWithMills(long epochMillis) {
        return DATETIME_FORMAT_NORMAL_SSS.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(epochMillis), ZoneId.systemDefault()));
    }

    /**
     * 获取yyyy-MM-dd HH:mm:ss格式的字符串
     */
    public static String getDatetimeNormalStr(long epochMillis) {
        return DATETIME_FORMAT_NORMAL.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(epochMillis), ZoneId.systemDefault()));
    }

    /**
     * 获取yyyy-MM-dd格式的字符串
     */
    public static String getDateNormalStr(long epochMillis) {
        return DATE_FORMAT_NORMAL.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(epochMillis), ZoneId.systemDefault()));
    }

    /**
     * 获取HH:mm:ss格式的字符串
     */
    public static String getTimeNormalStr(long epochMillis) {
        return TIME_FORMAT_NORMAL.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(epochMillis), ZoneId.systemDefault()));
    }

    /**
     * 获取yyyyMMddHHmmssSSS格式的字符串
     */
    public static String getDatetimeShortStrWithMills(long epochMillis) {
        return DATETIME_FORMAT_SHORT_SSS.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(epochMillis), ZoneId.systemDefault()));
    }

    /**
     * 获取yyyyMMddHHmmss格式的字符串
     */
    public static String getDatetimeShortStr(long epochMillis) {
        return DATETIME_FORMAT_SHORT.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(epochMillis), ZoneId.systemDefault()));
    }

    /**
     * 获取yyyyMMdd格式的字符串
     */
    public static String getDateShortStr(long epochMillis) {
        return DATE_FORMAT_SHORT.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(epochMillis), ZoneId.systemDefault()));
    }

    /**
     * 获取HHmmss格式的字符串
     */
    public static String getTimeShortStr(long epochMillis) {
        return TIME_FORMAT_SHORT.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(epochMillis), ZoneId.systemDefault()));
    }

    /**
     * 获取北京时间 "yyyy-MM-dd HH:mm:ss:SSS"
     */
    public static String getBeijingDateTimeNormalStrWithMills(long epochMillis) {
        return DATETIME_FORMAT_NORMAL_SSS.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(epochMillis), ZoneId.of("GMT+8")));
    }

    /**
     * 获取北京时间 "yyyy-MM-dd HH:mm:ss"
     */
    public static String getBeijingDateTimeNormalStr(long epochMillis) {
        return DATETIME_FORMAT_NORMAL.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(epochMillis), ZoneId.of("GMT+8")));
    }

    /**
     * 获取北京时间 "yyyyMMdd"
     */
    public static String getBeijingDateShortStr(long epochMillis) {
        return DATE_FORMAT_SHORT.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(epochMillis), ZoneId.of("GMT+8")));
    }

    /**
     * 获取格林威治时间：北京时间-8h  yyyy-MM-dd'T'HH:mm:ss.SSS
     *
     * @param epochMillis 时间戳毫秒
     * @return 格林威治时间字符串
     */
    public static String getGMTDateTime(long epochMillis) {
        return LocalDateTime.ofInstant(Instant.ofEpochMilli(epochMillis), ZoneId.of("GMT")).toString();
    }

    /**
     * 获取同一标准时间：北京时间-8h  yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
     *
     * @param epochMillis 时间戳毫秒
     * @return 格林威治时间字符串
     */
    public static String getUTCDateTime(long epochMillis) {
        return LocalDateTime.ofInstant(Instant.ofEpochMilli(epochMillis), ZoneId.of("UTC")).toString() + 'Z';
    }

    /**
     * 获取某一天的0点0分0秒0毫秒
     *
     * @param oneDay     某一天
     * @param offsetDays 偏移天数，如果不需要偏移则传入0
     */
    public static Date getBeginOfOneDay(Date oneDay, int offsetDays) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(oneDay);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        calendar.add(Calendar.DATE, offsetDays);
        return calendar.getTime();
    }

    /**
     * 获取某一天的23点59分59秒999毫秒
     *
     * @param oneDay     某一天
     * @param offsetDays 偏移天数，如果不需要偏移则传入0
     */
    public static Date getEndOfOneDay(Date oneDay, int offsetDays) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(oneDay);
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        calendar.add(Calendar.DATE, offsetDays);
        return calendar.getTime();
    }

    /**
     * 获取某一天偏移offsetDays后的日期
     *
     * @param oneDay     某一天
     * @param offsetDays 偏移天数
     */
    public static Date getDateByOneDayOffset(Date oneDay, int offsetDays) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(oneDay);
        calendar.add(Calendar.DATE, offsetDays);
        return calendar.getTime();
    }

    /**
     * 获取日期的字符串
     *
     * @param toFormat 转换的格式
     */
    public static String getDateStr(Date date, String toFormat) {
        SimpleDateFormat format = new SimpleDateFormat(toFormat);
        return format.format(date);
    }

    /**
     * 把 20200204121234 这样的时间转换为 2020-02-04 12:12:34
     *
     * @param origin 原始时间字符串
     * @return 转换后的字符串
     */
    public static String convertAsNormalDateString(String origin) {
        if (origin == null) {
            return null;
        }
        try {
            if (origin.matches("\\d{8}")) {
                SimpleDateFormat fmt = new SimpleDateFormat("yyyyMMdd");
                return getDateNormalStr(fmt.parse(origin).getTime());
            } else if (origin.matches("\\d{14}")) {
                SimpleDateFormat fmt = new SimpleDateFormat("yyyyMMddHHmmss");
                return getDatetimeNormalStr(fmt.parse(origin).getTime());
            }
        } catch (ParseException e) {
            throw new IllegalArgumentException(e);
        }
        throw new IllegalArgumentException(origin + "is invalid,String format is yyyyMMddHHmmss or yyyyMMdd");
    }

    private DateTimeUtil() {
    }
}
